﻿using System;
using System.Collections.Generic;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace DrivingGame
{
    class Car : GameObject
    {
        public static SpriteFont font;
        public static BoundingBox[] buildingBoundingBoxes;
        public Vector3 lastPosition;
        public bool collision = false;
        public bool isWinner = false;
        public int score = 10000;
        protected float speed = 0.0f;
        protected float acceleration = 0.0f;
        protected int gear = 1;
        protected bool free = true;
        protected int turn = 0;
        protected float[] topSpeeds;
        protected float[] accelerations;
        protected float maxReverseSpeed = 10.0f;
        protected float collisionCoefficient = 0.25f;
        protected float rotationSpeedPerSec = (float)Math.PI / 4;
        protected int millisecond = 0;
        protected int second = 0;
        protected int minute = 0;
        protected int ElapsedTime = 0;

        public BoundingBox carBoundingBox { get; protected set; }

        public Car()
        {
        }

        public void Accelerate()
        {
            free = false;

            if ((gear < topSpeeds.Length) && (speed > topSpeeds[gear]))
            {
                gear++;
            }
            if (gear == 0)
            {
                acceleration = accelerations[1];
            }
            else if (gear < topSpeeds.Length)
                acceleration = accelerations[gear];
            else
            {
                gear = topSpeeds.Length - 1;
                acceleration = 0;
                speed = topSpeeds[topSpeeds.Length - 1];
            }
        }

        public void Brake()
        {
            free = false;

            if ((gear > 0) && speed <= topSpeeds[gear - 1])
            {
                gear--;
            }
            if ((gear == 0) && (speed < -maxReverseSpeed))
            {
                acceleration = 0;
                speed = -maxReverseSpeed;
            }
            else
            {
                acceleration = -accelerations[gear] - 6.0f;
            }
        }

        public void Free()
        {
            free = true;

            if ((gear > 0) && (speed < topSpeeds[gear - 1]))
            {
                gear--;
            }

            acceleration = -accelerations[gear];
        }

        public void Left()
        {
            turn = -1;
        }

        public void Right()
        {
            turn = 1;
        }

        public void NoTurn()
        {
            turn = 0;
        }

        public void Update(GameTime gameTime, Car otherCar)
        {
            ElapsedTime += gameTime.ElapsedGameTime.Milliseconds;
            millisecond = ElapsedTime % 1000;
            second = ElapsedTime / 1000;
            if (second >= 60)
            {
                ElapsedTime = 0;
                minute += 1;
                second -= 60;
            }

            lastPosition = position;
            float time = ((float)gameTime.ElapsedGameTime.Milliseconds) / 1000;
            float rotationSpeed = rotationSpeedPerSec * time;
            float newRotation = rotationSpeed * turn;
            
            rotation = rotation * Quaternion.CreateFromAxisAngle(new Vector3(0, -1, 0), newRotation);
            float newSpeed = speed + acceleration * time;

            // If neither accelerator not brake is pressed car will come to stop as speed decreases
            // not start to move in opposite direction
            if ((free == true) && (newSpeed * speed <= 0.0f))
            {
                gear = 1;
                acceleration = accelerations[gear];
                speed = 0.0f;
            }
            else
            {
                speed = newSpeed;
            }

            float dist = speed * time;
            Vector3 addVector = Vector3.Transform(new Vector3(0, 0, 1), rotation);
            position += addVector * dist;

            Vector3[] carPoints = new Vector3[2];
            carPoints[0] = new Vector3(position.X - 0.8f, 0, position.Z - 1.5f);
            carPoints[1] = new Vector3(position.X + 0.8f, 0.6f, position.Z + 1.5f);
            carBoundingBox = BoundingBox.CreateFromPoints(carPoints);

            if (CollidesWithBuildings(carBoundingBox) || CollidesWith(otherCar))
            {
                this.score -= 100;
                collision = true;
            }
            else
                collision = false;

            if (collision)
            {
                position = lastPosition;
                speed = 0.0f;
                acceleration = 0.0f;
            }

            CheckWinner();
        }

        public bool CollidesWith(Car otherCar)
        {
            if (this.carBoundingBox.Contains(otherCar.carBoundingBox) == ContainmentType.Intersects || this.carBoundingBox.Contains(otherCar.carBoundingBox) == ContainmentType.Intersects)
                return true;
            return false;
        }

        public bool CollidesWithBuildings(BoundingBox boundingBox)
        {
            for (int i = 0; i < buildingBoundingBoxes.Length; i++)
                if (buildingBoundingBoxes[i].Contains(boundingBox) == ContainmentType.Intersects || buildingBoundingBoxes[i].Contains(boundingBox) == ContainmentType.Contains)
                    return true;
            return false;
        }

        public bool CollidesWithBuildings(BoundingSphere boundingSphere)
        {
            for (int i = 0; i < buildingBoundingBoxes.Length; i++)
                if (buildingBoundingBoxes[i].Contains(boundingSphere) == ContainmentType.Intersects || buildingBoundingBoxes[i].Contains(boundingSphere) == ContainmentType.Contains)
                    return true;
            return false;
        }

        public void CheckWinner()
        {
            if (WithinRange(this.position.X, 210.0f, 240.0f) && WithinRange(this.position.Z, -240.0f, -210.0f))
            {
                this.isWinner = true;
                this.score += 1000;
                this.score -= minute * 1000 + second * 100; 
            }
        }

        private bool WithinRange(float numberToCheck, float bottom, float top)
        {
            return (numberToCheck > bottom && numberToCheck < top);
        }

        public void DrawInfo(SpriteBatch spriteBatch)
        {
            spriteBatch.Begin();
            spriteBatch.DrawString(font, getTime(), new Vector2(100, 90), Color.White);
            spriteBatch.DrawString(font, getSpeed(), new Vector2(100, 50), Color.White);
            spriteBatch.End();
        }

        private string getSpeed()
        {
            return "Car Speed: " + (int)Math.Abs(this.speed * 3) + " KM/h";
        }

        private string getTime()
        {
            return "Time: " + (minute < 10 ? ("0" + minute.ToString()) : minute.ToString()) + ":" + (second < 10 ? ("0" + second.ToString()) : second.ToString()) + ":" + millisecond.ToString(); ;
        }
    }
}
